package com.example.websockettest.webSocket;

import com.alibaba.fastjson.JSONObject;
import com.example.websockettest.webSocket.MyTool.TalkToUser;
import com.example.websockettest.webSocket.MyTool.TxtAndType;
import com.example.websockettest.webSocket.MyTool.控制gpt指令集;
import com.example.websockettest.webSocket.MyTool.自由对话;
import com.example.websockettest.webSocket.entity.GameUser;
import com.example.websockettest.webSocket.entity.Wenzhang;
import com.example.websockettest.webSocket.service.LoginService;
import com.example.websockettest.webSocket.utils.SessionAndUid;
import com.example.websockettest.webSocket.utils.通用操作数据库;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static com.example.websockettest.webSocket.MyTool.自由对话.get历史消息;
import static com.example.websockettest.webSocket.ProxyPost.ProxyExample.response;

/**
 * @author pengshizhu
 * @date 2023-4-1
 */
@Component
//@ServerEndpoint(value = "/websocket", subprotocols = {"protocol"})
//定义 WebSocket 服务器，它将监听 "/web" 路径，并使用 "protocol" 子协议进行通信。
@ServerEndpoint(value = "/web", subprotocols = {"protocol"})
public class WebSocketServer extends 通用操作数据库 {

    private static LoginService loginService;
    @Autowired
    public void setLoginService(LoginService loginService){
        WebSocketServer.loginService = loginService;
    }

    private static int onlineCount = 0;
    private static ConcurrentHashMap<String, WebSocketServer> webSocketSet = new ConcurrentHashMap<>();
    private static List<SessionAndUid> sessionAndUidList=new ArrayList<>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private static Logger log = LogManager.getLogger(WebSocketServer.class);

    private static ApplicationContext applicationContext;

    public static void setApplicationContext(ApplicationContext applicationContext) {
        WebSocketServer.applicationContext = applicationContext;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        BigInteger bigInt = new BigInteger(session.getId(), 16); // 将sessionId转换为BigInteger类型
        String decimalString = bigInt.toString(); // 将BigInteger类型转换为十进制字符串
        webSocketSet.putIfAbsent(decimalString,this);
        sessionAndUidList.add(new SessionAndUid(decimalString));
        //接收到发送消息的人员编号
        addOnlineCount();           //在线数加1
        log.info("用户" + session.getId() + "连接成功！当前在线人数为" + getOnlineCount());
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("websocket IO异常");
        }

    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        BigInteger bigInt = new BigInteger(session.getId(), 16); // 将sessionId转换为BigInteger类型
        String decimalString = bigInt.toString(); // 将BigInteger类型转换为十进制字符串
        try {
            GameUser gameUser=gameUserMapper.selectGameUserById(SessionAndUid.getUid(sessionAndUidList, Integer.parseInt(decimalString)));
            gameUser.setStatus("0");
            gameUserMapper.updateGameUser(gameUser);
        } catch (Exception e) {

        }
       webSocketSet.remove(decimalString);

        //System.out.println(decimalString); // 输出十进制字符串
        SessionAndUid.remove(sessionAndUidList, Integer.parseInt(decimalString));
        subOnlineCount();           //在线数减1
        log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        try {
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        error.printStackTrace();

    }

    /**
     * 服务端主动推送消息
     *
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发送信息给指定ID用户，如果用户不在线则返回不在线信息给自己
     *
     * @param message
     * @throws IOException
     */

    public static void sendtouser(String s,String message) throws IOException {
        webSocketSet.get(s).sendMessage(message);
    }
    public static void sendtouser(long uid,String message){
        try {
            sendToUserByUid(uid,message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void sendToUserByUid(long uid,String message) throws IOException {
        String s="";
        for (SessionAndUid e:sessionAndUidList){
            if(e.getUid()==uid){
                s=e.getSessionId()+"";
                break;
            }
        }
        if(!s.equals(""))
            webSocketSet.get(s).sendMessage(message);
        else log.info("给他发消息时该用户未在线"+uid);
    }
    public void sendToUserByUid(String message) throws IOException {//当前会话
        String s="";
        s=this.session.getId()+"";
        if(!s.equals(""))
            webSocketSet.get(s).sendMessage(message);
        else log.info("给他发消息时该用户未在线");
    }





    /**
     * 发送信息给所有人
     *
     * @param
     * @throws IOException
     */
    public void sendtoAll(String message) throws IOException {//发送给全体在线用户
        for (String key : webSocketSet.keySet()) {
            try {
                webSocketSet.get(key).sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) throws IOException {

//    JSONObject jsonObject1=JSONObject.parseObject(message);
//    String ac=jsonObject1.getString("action");
//    long uid=jsonObject1.getLong("uid");
//    sendToUserByUid(uid,JSONObject.toJSONString(new MyRole()));

        // webSocketSet.putIfAbsent(message.split("-")[0],this);
        /*if(message.split("-")[1].equals("获取gameGoodsList具体信息")){
            List<GameGoodsList> gameGoodsListList=gameGoodsListMapper.selectGameGoodsListList(new GameGoodsList());
            sendtouser(message.split("-")[0],JSONObject.toJSONString(gameGoodsListList));
        }
        sendtouser(message.split("-")[0],"这是服务端发送的消息");*/
        System.out.println("这是客户端发送的消息"+message);
        JSONObject jsonObject = JSONObject.parseObject(message);
        if(jsonObject.getString("action")!=null&&jsonObject.getString("action").equals("心跳")){
            log.info("--------------心跳监听-----------");
        }else {

            JSONObject handle = loginService.handle(message);
            int uid= -1;

            if (handle != null && handle.getString("action") != null && handle.getString("action").equals("login")) {
                String id = handle.getString("uid");
                uid= Integer.parseInt(id);
                System.out.println(handle.toJSONString()+"登录信息");

                //webSocketSet.putIfAbsent(id, this);
                if(id!=null) {
                    BigInteger bigInt = new BigInteger(session.getId(), 16); // 将sessionId转换为BigInteger类型
                    String decimalString = bigInt.toString(); // 将BigInteger类型转换为十进制字符串
                    SessionAndUid.putIfAbsent(sessionAndUidList, Integer.parseInt(decimalString), Integer.parseInt(id));
                }
                    //加入set中
                if(id!=null){

                }
                    //sendToUserByUid(Long.parseLong(id),"sessionId is"+session.getId()+"uid is"+id);
                else {
                    id= jsonObject.getString("uid");
                }

                sendToUserByUid(Long.parseLong(id),handle.toJSONString());
                System.out.println(jsonObject.toJSONString());
                System.out.println(JSONObject.toJSONString(sessionAndUidList));
            }
            if(uid==-1){
                try {
                    uid = jsonObject.getInteger("uid");
                } catch (Exception e) {
                    log.info("该用户尚未登录");
                }
            }
            String res = "null_1";
            if(jsonObject.getString("action")!=null&&jsonObject.getString("action").equals("请求gpt")){
                try {
                    res=response(jsonObject.getString("text"));
                    System.out.println(res);
                } catch (IOException e) {
                    System.out.println(e.getMessage()+"错误信息");
                    sendToUserByUid(uid,"gpt异常");
                }
                TalkToUser response=new TalkToUser("回复",res);
                String a=JSONObject.toJSONString(response);
                System.out.println(a);
                sendToUserByUid(uid,a);
            }
           // sendtoAll("全部发送");
            // String[] ids = {handle.getString("uid")};
            //sendtouser(handle.getString("uid"),handle.toJSONString());
            actionImp(jsonObject,uid);
        }
    }

    private void actionImp(JSONObject jsonObject,long uid) throws IOException {
            String action= jsonObject.getString("action");


        //实现原生给gpt在客户端的访问
        if(action!=null&&action.equals("自由对话")){//简单的一问一答，自由提问
            sendToUser_Msg("msg", "等待chatgpt响应中", uid);
            String a=response(jsonObject.getString("userTxt"));
            if(a.equals("请求处理超时")){
                a=response(jsonObject.getString("userTxt"));
                sendToUser_Msg("回复", "请求超时正在重新生成相应", uid);
            }
            sendToUser_Msg("回复", a, uid);
        }
            if(action!=null&&action.equals("初始化面试对话")){
                sendToUser_Msg("msg", "chatGPT正在响应中....", uid);
                //初始化历史对话
                gptMapper.deleteGptByUid(uid);
                //初始化面试对话
                String response = "";
                response = response(控制gpt指令集.初始话场景模拟);
                if (response.equals("请求处理超时")) {
                    请求超时处理_初始化(uid, response);
                    System.out.println("初始化对话超时");
                    return;
                }
                自由对话.saveGptrMsg(response, uid);
                sendToUser_Msg("回复", response, uid);
            }
            if(action.equals("模拟面试对话")) {
                自由对话.saveUserMsg(jsonObject,uid);
                String response = "";
                try {
                    //get历史消息
                    response = response(get历史消息(uid),10);
                } catch (IOException e) {
                    response = response(控制gpt指令集.初始话场景模拟,15);
                }
                if (response.equals("请求处理超时")) {
                    请求超时处理_对话中(uid, response);
                    return;
                }
                自由对话.saveGptrMsg(response, uid);
                sendToUser_Msg("回复", response, uid);
            }
        if(action==null){
                return;
            }
            if(action!=null&&action.equals("请求情景分类")){
                String listType=JSONObject.toJSONString(getTxtAndType());
               System.out.println(listType);
                sendToUser_Msg("文章目录", listType, uid);
            }
        if(action!=null&&action.equals("changeUser")){
            // String listType= String.valueOf(getTxtType());
            changePassWord(jsonObject,uid);

        }

            if(action.equals("情景模式对话中")){
                String finger=jsonObject.getString("text").split("-")[0];
                String txt=jsonObject.getString("text").replace("--","__").split("-")[1];
                txt=txt.replace("__","--");
                if(finger.equals("文章")){
                  String txts= getShunXuDuiHua(txt,Integer.parseInt(jsonObject.getString("text").replace("--",".").split("-")[2]));
                  if (txts==null){
                      sendToUser_Msg("msg", "当前文章不存在", uid);
                      return;
                  }
                    sendToUser_Msg("回复", txts.split("-")[1], uid);
                    TalkToUser talk;
                    talk=new TalkToUser("msg",txts.split("-")[0]);
                    sendToUserByUid(uid,JSONObject.toJSONString(talk));//读者读的
                }
                if(finger.equals("分类")){
                    sendToUser_Msg("msg", String.valueOf(getTxts(txt)) + "选择文章时，请输入 文章-“文章名”-“文章顺序”", uid);
                }

            }
    }

    private static void 请求超时处理_初始化(long uid, String response) {

            Thread thread = new Thread() {
                @Override
                public void run() {
                    String response="";
                    int num=0;
                    while (!response.equals("请求处理超时")) {
                        try {
                             response = response(控制gpt指令集.初始话场景模拟,10);
                             if(!response.equals("请求处理超时")){
                                sendToUser_Msg("回复",response,uid);
                                return;
                             }
                        } catch (Exception e) {
                        }
                        try {
                            sendToUser_Msg("msg", "请求超时正在重新生成相应", uid);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        try {
                            Thread.sleep(10000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        num++;
                        if(num>5){
                            try {
                                sendToUser_Msg("msg","请求错误，请管理员检查后端代理连接", uid);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                            break;
                        }
                    }
                    if(num<5){
                        自由对话.saveGptrMsg(response, uid);
                    }
                }

            };
            thread.start();
    }
    private static void 请求超时处理_对话中(long uid, String response) {

        Thread thread = new Thread() {
            @Override
            public void run() {
                String response="";
                int num=0;
                while (!response.equals("请求处理超时")) {
                    try {
                        response = response(get历史消息(uid),10);
                        sendToUser_Msg("回复",response,uid);
                        return;
                    } catch (IOException e) {

                    }
                    try {
                        sendToUser_Msg("回复", "请求超时正在重新生成相应", uid);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    num++;
                    if(num>5){
                        try {
                            sendToUser_Msg("msg","请求错误，请管理员检查后端代理连接", uid);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        break;
                    }
                }
                if(num<5){
                    自由对话.saveGptrMsg(response, uid);
                }
            }
        };
        thread.start();
    }

    public static void sendToUser_Msg(String action, String txt, long uid) throws IOException {
        TalkToUser talkToUser=new TalkToUser(action, txt);
        sendToUserByUid(uid,JSONObject.toJSONString(talkToUser));
    }

    private static StringBuilder getTxtType() {//获取文章类型
        List <Wenzhang> wenzhangList=wenzhangMapper.selectWenzhangList(new Wenzhang());
        List<String> txtType=new ArrayList<>();
        for (Wenzhang e:wenzhangList){
            if(txtType.contains(e.get类型())){
                continue;
            }
            txtType.add(e.get类型());
        }
        StringBuilder txt= new StringBuilder();
        for(String e:txtType){
            txt.append(",").append(e);
        }
        return new StringBuilder(txt.substring(1, txt.length()));
    }

    private static StringBuilder getTxts(String type) {//获取文章
        List <Wenzhang> wenzhangList=wenzhangMapper.selectWenzhangBy文章类型(type);
        List<String> txtType=new ArrayList<>();
        for (Wenzhang e:wenzhangList){
            if(txtType.contains(e.getName())){
                continue;
            }
            txtType.add(e.getName());
        }
        StringBuilder txt= new StringBuilder();
        for(String e:txtType){
            txt.append(",").append(e);
        }
        return new StringBuilder(txt.substring(1, txt.length()));
    }

    public static String getShunXuDuiHua(String name,int shunxu){
        List<Wenzhang> wenzhangList=wenzhangMapper.selectWenzhangByName(name);
        for(Wenzhang e:wenzhangList){
            if(e.get文章顺序()==shunxu){
                return e.getUser()+"-"+e.getAssistant()+"-"+e.get文章顺序();
            }
        }
    return null;
    }

    public static List<TxtAndType> getTxtAndType(){
        String type= String.valueOf(getTxtType());
        List<TxtAndType> txtAndTypeList=new ArrayList<>();
        for(String e:type.split(",")){
            txtAndTypeList.add(new TxtAndType(e, Arrays.asList(String.valueOf(getTxts(e)).split(","))));
        }
        return txtAndTypeList;

    }

    public static void changePassWord(JSONObject jsonObject,long uid) throws IOException {
        String beforepassword=gameUserMapper.selectGameUserById(uid).getPassword();
        if(jsonObject.getString("before").equals(beforepassword)){
            GameUser gameUser=gameUserMapper.selectGameUserById(uid);
            gameUser.setPassword(jsonObject.getString("after"));
            gameUserMapper.updateGameUser(gameUser);
            sendToUser_Msg("alert","密码修改成功",uid);
            System.out.println("密码修改成功");
        }else {
            sendToUser_Msg("alert","原密码错误",uid);
            System.out.println("原密码错误");
        }
    }


}

